<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>策略模式（strategy-pattern）</title>
    <style type="text/css">
        fieldset{
            border: none;
            display: flex;
            align-items: center;
            font-size: 18px;
            color: #666;
        }

        input {
            padding-left: 15px;
            line-height: 30px;
            border-style: solid;
            border-color: #EEE;
            letter-spacing: 2px;
            outline: none;
        }

        .btn-submit {
            width: 100px;
            line-height: 30px;
            color: #666;
            font-size: 18px;
            border-color: #eee;
            border-radius: 5px;
            /* border-style: ridge; */
            cursor: pointer;
            background-color: #fafafa;
        }
        #tip{font-size: 12px;color: #f00;}
    </style>
</head>
<body>
    <h2>使用策略模式进行表单验证</h2>
    <form action="/" class="form">
        <fieldset>
            <label for="username">用&ensp;&ensp;户：</label>
            <input type="text" name="username"/>
        </fieldset>
        <fieldset>
            <label for="password">密&ensp;&ensp;码：</label>
            <input type="password" name="password"/>
        </fieldset>
        <fieldset>
            <button class="btn-submit">提交</button>
        </fieldset>
    </form>
    <div id="tip"></div>
    <script type="text/javascript">
        // 首先定义校验规则
        const strategies = {
            noEmpty: function (value, errMsg) {
                if (value.trim() === "") {
                    return errMsg
                }
            },
            minLength:function(value, length, errMsg) {
                if(!value || value.length < length) {
                    return errMsg
                }
            },
            maxLength:function(value, length, errMsg) {
                if(value.length > length) {
                    return errMsg
                }
            }
        }

        //接着设置验证器

        var Validator = function(strategies) {
            this.strategies = strategies
            this.cache = [] // 存储校验规则
        }

        Validator.prototype.add = function(dom, rules) {
            rules.forEach(rule => {
                this.cache.push(() => {
                    let value = dom.value
                    let arr = rule.rule.split(":")
                    let name = arr.shift()
                    let params = [value, ...arr, rule.errMsg]
                    return this.strategies[name].apply(dom,params)
                })
            });
        }

        Validator.prototype.validate = function(dom, rules, errMsg) {
            //遍历cache里面的校验函数
            for (let i = 0, validateFun; validateFun = this.cache[i++];) {
                const message = validateFun();
                // 返回报错信息 终止验证并且抛出异常
                if(message) return message 
            }
        }

        //最后校验
        var form = document.querySelector("form")
        //提交表单
        form.onsubmit = function(event) {
            event.preventDefault()
            const message = validate()
            const tip = document.getElementById("tip")
            if(message) {
                tip.innerHTML = message
                tip.style.color = ""
            } else {
                tip.innerHTML = '验证通过'
                tip.style.color = "#0016ff"
            }
        }

        //验证函数
        function validate() {
            const validator = new Validator(strategies)
            // 添加验证规则
            validator.add(form.username, [
               { rule: "noEmpty", errMsg:"用户名不为空！"},
               { rule: "minLength:3", errMsg:"用户名长度大于3"},
            ])
            validator.add(form.password, [
               { rule: "minLength:6", errMsg:"密码长度大于6！"},
               { rule: "maxLength:10", errMsg:"密码最大长度为10！"},
            ])
            return validator.validate()
        } 
    </script>
</body>
</html>